package ui;

import file.FileHandler;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Callback;
import model.Attribute;
import model.Database;
import model.Table;
import mongodb.MongoDb;
import ui.component.AttributeView;
import ui.component.ContentView;
import ui.component.IndexView;
import ui.component.QueryView;
import ui.component.TextFieldTreeCell;

/**
 *
 * @author Merli András-Bertalan
 */
public class DatabaseHandler extends Application {

    private final Node databasesIcon = null;
//            new ImageView(new Image(getClass().getResourceAsStream("databases.png")));
    private final Node tablesIcon = null;
//            new ImageView(new Image(getClass().getResourceAsStream("tables.png")));
//    private List<Database> databases = Arrays.<Database>asList();
    private final TreeItem<String> rootNode =
            new TreeItem<>("Databases", databasesIcon);
//    private ObservableList<Attribute> attributes =
//            FXCollections.observableArrayList(
//            new Attribute("name", "string", false, false),
//            new Attribute("email", "string", true, true));
    private Button saveCurrentStateButton;
    private Button queryDesignerButton;
    private TreeView<String> treeView;
    private VBox emptyRightBox;
    private List<Database> databases;
    private final DatabaseHandler self = this;
    private TreeItem<String> selectedItem;

    @Override
    public void start(Stage stage) {
        emptyRightBox = new VBox();
        System.out.println("mongo load...");
        databases = FileHandler.loadDatabases();
        System.out.println("mongo finished...");
        try {
            MongoDb.loadContentFromDatabaseToTablesAndIndexTables(databases);
        } catch (UnknownHostException ex) {
            Logger.getLogger(DatabaseHandler.class.getName()).log(Level.SEVERE, null, ex);
        }

        for (Database database : databases) {
            TreeItem databaseNode = new TreeItem(database.getName(), null);
            TreeItem tablesNode = new TreeItem("Tables", tablesIcon);
            rootNode.getChildren().add(databaseNode);
            databaseNode.getChildren().add(tablesNode);
            for (Table table : database.getTables()) {
                tablesNode.getChildren().add(new TreeItem(table.getName(), null));
            }
        }

        stage.setTitle(
                "Database Management");

        final AttributeView attributeViewBox = new AttributeView();
        final ContentView contentViewBox = new ContentView();
        final QueryView queryViewBox = new QueryView();
        final IndexView indexViewBox = new IndexView();
        VBox leftBox = new VBox();
        VBox vBox = new VBox();
        final SplitPane splitPane = new SplitPane();
        splitPane.getItems().add(leftBox);
        splitPane.setDividerPositions(0.3, 0.7);
        vBox.getChildren().add(splitPane);

        // create manageTableOptionsBox
        final VBox manageTableOptionsBox = new VBox();
        Button toAttributeViewButton = new Button("Manage Attributes");
        toAttributeViewButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                if (!splitPane.getItems().contains(attributeViewBox)) {
                    splitPane.getItems().remove(queryViewBox);
                    splitPane.getItems().remove(emptyRightBox);
                    splitPane.getItems().remove(contentViewBox);
                    splitPane.getItems().remove(manageTableOptionsBox);
                    splitPane.getItems().remove(indexViewBox);
                    splitPane.getItems().add(attributeViewBox);
                }
                Database selectedDatabase = getDatabaseByName(selectedItem.getParent().getParent().getValue());
                Table selectedTable = getTableByDatabaseAndTableName(selectedDatabase, selectedItem.getValue());
                attributeViewBox.updateUi(selectedTable, selectedDatabase.getTables());
            }
        });
        Button toContentViewButton = new Button("Manage Content");
        toContentViewButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                if (!splitPane.getItems().contains(contentViewBox)) {
                    splitPane.getItems().remove(emptyRightBox);
                    splitPane.getItems().remove(attributeViewBox);
                    splitPane.getItems().remove(manageTableOptionsBox);
                    splitPane.getItems().remove(indexViewBox);
                    splitPane.getItems().add(contentViewBox);
                }
                Database selectedDatabase = getDatabaseByName(selectedItem.getParent().getParent().getValue());
                Table selectedTable = getTableByDatabaseAndTableName(selectedDatabase, selectedItem.getValue());
                contentViewBox.updateUi(selectedDatabase, selectedTable, selectedDatabase.getIndexTables(), self);
            }
        });
        Button toIndexViewButton = new Button("Manage Indexes");
        toIndexViewButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                if (!splitPane.getItems().contains(indexViewBox)) {
                    splitPane.getItems().remove(queryViewBox);
                    splitPane.getItems().remove(emptyRightBox);
                    splitPane.getItems().remove(attributeViewBox);
                    splitPane.getItems().remove(manageTableOptionsBox);
                    splitPane.getItems().remove(contentViewBox);
                    splitPane.getItems().add(indexViewBox);
                }
                Database selectedDatabase = getDatabaseByName(selectedItem.getParent().getParent().getValue());
                Table selectedTable = getTableByDatabaseAndTableName(selectedDatabase, selectedItem.getValue());
                indexViewBox.updateUi(selectedDatabase, selectedTable, self);
            }
        });
        manageTableOptionsBox.getChildren().addAll(toAttributeViewButton, toContentViewButton, toIndexViewButton);

        final Scene scene = new Scene(vBox, 1000, 500);

        scene.setFill(Color.LIGHTGRAY);
        treeView = new TreeView<>(rootNode);

        treeView.setEditable(
                true);
        treeView.setCellFactory(
                new Callback<TreeView<String>, TreeCell<String>>() {
            @Override
            public TreeCell<String> call(TreeView<String> p) {
                return new TextFieldTreeCell(self);
            }
        });

        leftBox.getChildren()
                .add(treeView);

        treeView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
            @Override
            public void changed(ObservableValue observable, Object oldValue,
                    Object newValue) {
                selectedItem = (TreeItem<String>) newValue;
                if (selectedItem.getParent() != null && selectedItem.getParent().getValue().equals("Tables")) {
                    splitPane.getItems().remove(queryViewBox);
                    splitPane.getItems().remove(attributeViewBox);
                    splitPane.getItems().remove(contentViewBox);
                    splitPane.getItems().remove(emptyRightBox);
                    splitPane.getItems().remove(indexViewBox);
                    if (!splitPane.getItems().contains(manageTableOptionsBox)) {
                        splitPane.getItems().add(manageTableOptionsBox);
                    }
                } else {
                    splitPane.getItems().remove(queryViewBox);
                    splitPane.getItems().remove(manageTableOptionsBox);
                    splitPane.getItems().remove(attributeViewBox);
                    splitPane.getItems().remove(contentViewBox);
                    splitPane.getItems().remove(indexViewBox);
                    if (!splitPane.getItems().contains(emptyRightBox)) {
                        splitPane.getItems().add(emptyRightBox);
                    }
                }
            }
        });

        saveCurrentStateButton = new Button("Save current state");
        saveCurrentStateButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                if (splitPane.getItems().contains(attributeViewBox)) {
                    attributeViewBox.saveCurrentState();
                }
                if (splitPane.getItems().contains(contentViewBox)) {
                    contentViewBox.saveCurrentState();
                }
                saveCurrentState();
            }
        });

        queryDesignerButton = new Button("Query Designer");
        queryDesignerButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                if (!splitPane.getItems().contains(queryViewBox)) {
                    splitPane.getItems().remove(emptyRightBox);
                    splitPane.getItems().remove(attributeViewBox);
                    splitPane.getItems().remove(manageTableOptionsBox);
                    splitPane.getItems().remove(contentViewBox);
                    splitPane.getItems().add(queryViewBox);
                }
                Database selectedDatabase = getDatabaseByName(selectedItem.getParent().getParent().getValue());
                queryViewBox.updateUi(selectedDatabase, selectedDatabase.getTables(), self);
            }
        });

        leftBox.getChildren().addAll(saveCurrentStateButton, queryDesignerButton);

        stage.setScene(scene);

        stage.show();
    }

    public void saveCurrentState() {
        try {
            FileHandler.saveDatabases(databases);
            System.out.println("mongo delete...");
            MongoDb.deleteDatabases();
            System.out.println("mongo save...");
            MongoDb.saveDatabases(databases);
            System.out.println("mongo finished.");
        } catch (UnknownHostException ex) {
            Logger.getLogger(DatabaseHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void addDatabase(String databaseName) {
        databases.add(new Database(databaseName));
    }

    public void deleteDatabase(String databaseName) {
        Database database = getDatabaseByName(databaseName);
        if (database != null) {
            databases.remove(database);
        }
    }

    public void addTableToDatabase(String databaseName, String tableName) {
        Database database = getDatabaseByName(databaseName);
        if (database != null) {
            Table table = new Table(tableName, new LinkedList<Attribute>());
            database.addTable(table);
        }
    }

    public void deleteTableFromDatabase(String databaseName, String tableName) {
        Database database = getDatabaseByName(databaseName);
        if (database != null) {
            Table table = getTableByDatabaseAndTableName(database, tableName);
            database.deleteTable(table);
        }
    }

    public Database getDatabaseByName(String databaseName) {
        for (Database database : databases) {
            if (database.getName().equals(databaseName)) {
                return database;
            }
        }
        return null;
    }

    public void renameDatabase(String oldDatabaseName, String newDatabaseName) {
        Database database = getDatabaseByName(oldDatabaseName);
        database.setName(newDatabaseName);
    }

    public void renameTable(String databaseName, String oldTableName, String newTableName) {
        Database database = getDatabaseByName(databaseName);
        Table table = getTableByDatabaseAndTableName(database, oldTableName);
        table.setName(newTableName);
    }

//    public Table getTableByDatabaseNameAndTableName(String databaseName, String tableName) {
//        Database database = getDatabaseByName(databaseName);
//        if (database == null) {
//            return null;
//        }
//        return getTableByDatabaseAndTableName(database, tableName);
//    }
    public Table getTableByDatabaseAndTableName(Database database, String tableName) {
        for (Table table : database.getTables()) {
            if (table.getName().equals(tableName)) {
                return table;
            }
        }
        return null;
    }

    public Table getIndexTableByDatabaseAndTableName(Database database, String tableName) {
        for (Table table : database.getIndexTables()) {
            if (table.getName().equals(tableName)) {
                return table;
            }
        }
        return null;

    }

    /**
     * The main() method is ignored in correctly deployed JavaFX application.
     * main() serves only as fallback in case the application can not be
     * launched through deployment artifacts, e.g., in IDEs with limited FX
     * support. NetBeans ignores main().
     *
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}
